#!/usr/bin/env python
#
# Copyright (C) 2005-2020 ABINIT Group (Yann Pouillon)
#
# This file is part of the ABINIT software package. For license information,
# please see the COPYING file in the top-level directory of the ABINIT source
# distribution.
#
from __future__ import print_function, division, absolute_import #, unicode_literals

try:
    from ConfigParser import ConfigParser
except ImportError:
    from configparser import ConfigParser
from time import gmtime,strftime

try:
    from commands import getoutput
except:
    from subprocess import getoutput
import os
import re
import sys

class MyConfigParser(ConfigParser):

  def optionxform(self,option):
    return str(option)

# ---------------------------------------------------------------------------- #

#
# Main program
#

# Initial setup
my_name    = "make-doc-options"
my_configs = ["config/specs/options.conf"]
my_output  = "doc/build/config-template.ac9"

# Check if we are in the top of the ABINIT source tree
if ( not os.path.exists("configure.ac") or
     not os.path.exists("src/98_main/abinit.F90") ):
  print("%s: You must be in the top of an ABINIT source tree." % my_name)
  print("%s: Aborting now." % my_name)
  sys.exit(1)

# Read config file(s)
cnf = MyConfigParser()
for cnf_file in my_configs:
  if ( not os.path.exists(cnf_file) ):
    print("%s: Could not find config file (%s)." % (my_name,cnf_file))
    print("%s: Aborting now." % my_name)
    sys.exit(2)

# What time is it?
now = strftime("%Y/%m/%d %H:%M:%S +0000",gmtime())

# Init
cnf.read(my_configs[0])
re_en = re.compile("enable_")
re_gr = re.compile("group_")
re_wi = re.compile("with_")
all_args = cnf.sections()
all_args.sort()
ac_args = { "enable":list(), "group":list(), "with":list() }
for arg in all_args:
  arg_stat = cnf.get(arg,"status")
  if ( (arg_stat != "removed") and (arg_stat != "dropped") ):
    if ( re_en.match(arg) ):
      ac_args["enable"].append(arg)
    elif ( re_gr.match(arg) ):
      ac_args["group"].append(arg)
    elif ( re_wi.match(arg) ):
      ac_args["with"].append(arg)
    else:
      sys.stderr.write("%s: Warning: unknown option type\n" % (my_name))
ac_args["enable"].sort()
ac_args["group"].sort()
ac_args["with"].sort()

# Process arguments
defaults = ""
parse = ""
for arg in ("enable","with"):
  m4.write("\n  dnl\n  dnl --%s arguments\n  dnl\n" % (arg))
  defaults += "\n  dnl\n  dnl --%s arguments\n  dnl\n\n" % (arg)
  for opt in ac_args[arg]:
    var = re.sub(arg+"_","",opt)
    opt_name = re.sub("_","-",var)
    opt_desc = cnf.get(opt,"description")
    opt_stat = cnf.get(opt,"status")
    try:
      opt_dflt = cnf.get(opt,"default")
    except:
      opt_dflt = None
    try:
      opt_nega = cnf.get(opt,"negative")
    except:
      opt_nega = ""
    try:
      opt_vals = cnf.get(opt,"values")
    except:
      opt_vals = None
    if ( opt_stat == "hidden" ):
      parse += """
  dnl Hidden option: %s
  ac_configure_args="${ac_configure_args} --%s=\\\"${%s}\\\""
""" % \
        (opt,re.sub("_","-",opt),opt)
    else:
      m4.write("\n  AC_ARG_%s(%s,\n" % (arg.upper(),opt_name) \
        + "    AC_HELP_STRING([--%s-%s],\n      [%s (default: %s)]))\n" % \
          (arg,opt_name,opt_desc,opt_dflt))

      if ( opt_dflt is not None ):
        defaults += "  if test \"${%s_%s}\" = \"\"; then\n    %s_%s=\"%s\"\n  fi\n" % \
          (arg,var,arg,var,opt_dflt)

      if ( arg == "with" ):
        defaults += "  if test \"${%s_%s}\" = \"no\"; then\n    %s_%s=\"%s\"\n  fi\n" % \
          (arg,var,arg,var,opt_nega)

      if ( opt_vals is not None ):
        parse += "\n"+parse_opt(opt,opt_vals)
      elif ( arg == "enable" ):
        parse += "\n"+parse_opt(opt,"no yes")

      m4.write("  AC_SUBST(%s_%s)\n" % (arg,var))

# Finish writing define macro
m4.write(macro_define_footer())

# Start writing setup macro
m4.write(macro_setup_header())

# Process arguments
m4.write(defaults)

# Finish writing setup macro
m4.write(macro_setup_footer())

# Start writing backup macro
m4.write(macro_backup_header())

# Process arguments
for arg in ("enable","with"):
  m4.write("\n  dnl\n  dnl --%s arguments\n  dnl\n" % (arg))
  for opt in ac_args[arg]:
    var = re.sub(arg+"_","",opt)
    m4.write("  cmd_%s_%s=\"${%s_%s}\"\n" % (arg,var,arg,var))

# Do not forget "prefix"
m4.write("""
  dnl
  dnl Prefix
  dnl
  if test "${prefix}" != "NONE"; then
    cmd_prefix="${prefix}"
  fi
""")

# Finish writing backup macro
m4.write(macro_backup_footer())

# Start writing recall macro
m4.write(macro_recall_header())

# Process arguments
for arg in ("enable","with"):
  m4.write("\n  dnl\n  dnl --%s arguments\n  dnl\n" % (arg))
  for opt in ac_args[arg]:
    var = re.sub(arg+"_","",opt)
    m4.write("\n  if test \"${cmd_%s_%s}\" != \"\"; then\n    %s_%s=\"${cmd_%s_%s}\"\n  fi\n" % \
      (arg,var,arg,var,arg,var))

# Do not forget "prefix"
m4.write("""
  dnl
  dnl Prefix
  dnl
  if test "${cmd_prefix}" != ""; then
    prefix="${cmd_prefix}"
  fi
""")

# Finish writing recall macro
m4.write(macro_recall_footer())

# Build changed macro
changed = ""

for arg in all_args:

  # Init
  arg_stat = cnf.get(arg,"status")
  try:
    arg_repl = cnf.get(arg,"use_instead")
  except:
    arg_repl = ""

  # Removed options
  if ( (arg_stat == "removed") or (arg_stat == "dropped") ):
    arg1 = re.sub("_","-",arg)
    changed += "\n  dnl Removed --%s option" % (arg1)
    if ( arg_stat == "removed" ):
      changed += "\n  AC_MSG_NOTICE([ * --%s removed])" % (arg1)
      if ( arg_repl != "" ):
        changed += "\n  AC_MSG_NOTICE([   === please use --%s instead ===])" % \
          (re.sub("_","-",arg_repl))
    changed += """
  if test "${%s}" != ""; then
    AC_MSG_ERROR([removed option --%s has been used])
  fi
""" % (re.sub("-","_",arg1),arg1)

  # New options
  elif ( arg_stat == "new" ):
    arg2 = re.sub("_","-",arg)
    changed += "\n  dnl New --%s option\n" % (arg2)
    changed += "  AC_MSG_NOTICE([ * new option --%s is available])\n" % (arg2)

  # Changed UIs
  elif ( re.match("changed",arg_stat) ):
    arg1 = re.sub("_","-",arg)
    changed += """
  dnl UI change for --%s option
  AC_MSG_NOTICE([ * --%s has a new meaning])
  AC_MSG_NOTICE([   please check that --%s="${%s}" is OK for you])
""" % (arg1,arg1,arg1,re.sub("-","_",arg1))

  # Renamed options
  elif ( re.match("renamed",arg_stat) ):
    arg1 = re.sub("_","-",arg_stat.split()[1])
    arg2 = re.sub("_","-",arg)
    changed += """
  dnl --%s > --%s
  AC_MSG_NOTICE([ * --%s renamed --%s])
  if test "${%s}" != ""; then
    AC_MSG_ERROR([renamed option --%s has been used])
  fi
""" % (arg1,arg2,arg1,arg2,re.sub("-","_",arg1),arg1)

# Write changed macro
m4.write(re.sub("@MACRO@",changed,macro_changed_template()))

# Write parse macro
m4.write(re.sub("@MACRO@",parse,macro_parse_template()))

# Finish
m4.close()

tmp = getoutput("./config/scripts/add-header-typed Autoconf %s" % (my_output))
if ( tmp != "" ):
  print(tmp)

# Write option dumper (for debugging)
dumper = open("config.dump.in","a")
dumper.write("# Command-line options\n")
for arg in all_args:
  arg_stat = cnf.get(arg,"status")
  if ( (arg_stat != "hidden") and (arg_stat != "removed") ):
    var = re.sub("-","_",opt_name)
    dumper.write("%s=\"@%s@\"\n" % (arg,arg))
dumper.write("\n")
dumper.close()
